package cn.zwx.mvcframework.webmvc.servlet;

import cn.zwx.mvcframework.annotation.ZwxRequestParam;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * @author zhangwenxue
 */
public class ZwxHandlerAdapter {
    public ZwxModelAndView handler(HttpServletRequest req, HttpServletResponse resp, ZwxHandlerMapping handlerMapping) throws InvocationTargetException, IllegalAccessException {
        // 1.解析参数
        //将参数名称和参数的位置，这种关系保存起来
        Map<String,Integer> paramIndexMapping = new HashMap<>(8);
        Method method = handlerMapping.getMethod();
        // 获取参数上的注解
        int parameterCount = method.getParameterCount();
        Object result = null;
        if (parameterCount == 0 ){
            // 没有参数直接返回
            result = method.invoke(handlerMapping.getController());
        }else {
            // 解析参数上面的注解
            Annotation[][] parameterAnnotations = method.getParameterAnnotations();
            for (int i = 0; i < parameterAnnotations.length; i++) {
                for (Annotation annotation : parameterAnnotations[i]) {
                    if (annotation instanceof ZwxRequestParam){
                        // 获取注解里面的定义的参数名称
                        String paramName = ((ZwxRequestParam) annotation).value();
                        paramIndexMapping.put(paramName,i);
                    }
                }
            }

            // 获取形参列表 
            Class<?> [] paramTypes = method.getParameterTypes();
            // 处理参数有 HttpServletRequest、HttpServletResponse 情况
            for (int i = 0; i < paramTypes.length; i++) {
                Class<?> paramType = paramTypes[i];
//                if (paramType == HttpServletRequest.class || paramType == HttpServletResponse.class){
                    paramIndexMapping.put(paramType.getName(),i);
//                }
            }
            // 获取实参列表 
            Map<String,String[]> params = req.getParameterMap();
            // 按照顺序 保存参数值
            Object [] paramValues = new Object[paramTypes.length];
            for (Map.Entry<String, String[]> entry: params.entrySet()) {
                //处理下特殊字符
                String value = Arrays.toString(params.get(entry.getKey()))
                        .replaceAll("\\[|\\]","")
                        .replaceAll("\\s+",",");
                // 不存在的直接
                if(!paramIndexMapping.containsKey(entry.getKey())){continue;}
                // 获取参数名称 
                Integer index = paramIndexMapping.get(entry.getKey());
                //允许自定义的类型转换器Converter
                paramValues[index] = this.castStringValue(value,paramTypes[index]);

            }
            // 处理 HttpServletRequest  HttpServletResponse
            if(paramIndexMapping.containsKey(HttpServletRequest.class.getName())){
                int index = paramIndexMapping.get(HttpServletRequest.class.getName());
                paramValues[index] = req;
            }

            if(paramIndexMapping.containsKey(HttpServletResponse.class.getName())){
                int index = paramIndexMapping.get(HttpServletResponse.class.getName());
                paramValues[index] = resp;
            }
            // 2.反射调用
            result = method.invoke(handlerMapping.getController(),paramValues);
        }
      

        // 3.封装结果为ModelAndView
        if(result == null){return null;}
        /**
         * 这里暂时之处理 返回ZwxModelAndView对象其他对象暂时不处理
         */
        boolean isModelAndView = method.getReturnType() == ZwxModelAndView.class;
        if(isModelAndView){
            return (ZwxModelAndView)result;
        }else {
            HashMap<String, Object> hashMap = new HashMap<>(4);
            hashMap.put("result",result);
            return new ZwxModelAndView(null,hashMap);
        }
    }

    /**
     * 自定义类型参数转换
     * @param value 值
     * @param paramType 转换类型
     * @return 返回类型
     */
    private Object castStringValue(String value, Class<?> paramType) {
        if(String.class == paramType){
            return value;
        }else if(Integer.class == paramType){
            return Integer.valueOf(value);
        }else if(Double.class == paramType){
            return Double.valueOf(value);
        }else {
            if(value != null){
                return value;
            }
            return null;
        }
    }
}
